<?php
class MVC_PathCorrector implements MVC_PathCorrector_Interface {

    private $_strRequestDelimiter = '/';


    private $_arRulesForCorrectionRequest = array();


    private $_arDefaultRoutes = array();


    private $_arParamFilter = array();


    const PHP_NAME_PATTERN      = '/^[a-zA-Z_][0-9a-zA-Z_]*$/';
    const GET_REQUEST_DELIMITER = '?';
    const DEFAULT_RULE_DELIMITER = '/';


    public function __construct ($arRulesForCorrectionRequest, $arDefaultRoutes, $arParamFilter, $strRequestDelimiter = '/') {
        $this->setRulesForCorrectionRequest($arRulesForCorrectionRequest);
        $this->setDefaultRoutes($arDefaultRoutes);
        $this->setParamFilter($arParamFilter);
        $this->setRequestDelimiter($strRequestDelimiter);
    }


    public function requestCorrect ($strMvcRequest) {
        $strMvcRequest = strtolower($strMvcRequest);

        if (substr_count($strMvcRequest, self::GET_REQUEST_DELIMITER) > 0) {
            $strMvcRequest = substr($strMvcRequest, 0, -strlen(strrchr($strMvcRequest, self::GET_REQUEST_DELIMITER)));
        }

        if (substr($strMvcRequest, 0, 1) == $this->getRequestDelimiter()) {
            $strMvcRequest = substr($strMvcRequest, 1);
        }

        if (substr($strMvcRequest, -1, 1) == $this->getRequestDelimiter()) {
            $strMvcRequest = substr($strMvcRequest, 0, -1);
        }

        $iFirstPosDelimiter = strlen(strchr($strMvcRequest, $this->getRequestDelimiter()));
        if (empty($iFirstPosDelimiter)) {
            $strPartPath = $strMvcRequest;
        } else {
            $strPartPath = substr($strMvcRequest, 0, -$iFirstPosDelimiter);
        }

        $bIsRuleDelimiterReplace = false;
        if ($this->getRequestDelimiter() != self::DEFAULT_RULE_DELIMITER) {
            $bIsRuleDelimiterReplace = true;
        }

        foreach ($this->_arRulesForCorrectionRequest as $pattern => $replacement){
            if ($bIsRuleDelimiterReplace) {
                $replacement = str_replace(self::DEFAULT_RULE_DELIMITER, $this->getRequestDelimiter(), $replacement);
            }
            $strPartPath = preg_replace($pattern, $replacement, $strPartPath);
        }

        $strMvcRequest = $strPartPath.strchr($strMvcRequest, $this->getRequestDelimiter());

        if (empty($strMvcRequest)) {
            $strMvcRequest = $this->getDefaultRoute('controller').
                             $this->getRequestDelimiter().
                             $this->getDefaultRoute('method');
        }

        if (substr_count($strMvcRequest, $this->getRequestDelimiter()) == 0) {
            $strMvcRequest = $strMvcRequest.
                             $this->getRequestDelimiter().
                             $this->getDefaultRoute('method');
        }

        return $strMvcRequest;
    }


    public function controllerCorrect ($strControllerName) {
        if (!preg_match(self::PHP_NAME_PATTERN, $strControllerName)) {
            return '';
        }
        return ucfirst(strtolower($strControllerName));
    }


    public function methodCorrect ($strMethodName) {
        if (substr($strMethodName, 0, 1) == '_') {
            return '';
        }
        if (!preg_match(self::PHP_NAME_PATTERN, $strMethodName)) {
            return '';
        }
        return strtolower($strMethodName);
    }


    public function paramCorrect ($arParam) {
        if(empty($arParam)) {
            return array();
        }

        foreach ($arParam as $k => $v) {
            if (!preg_match($this->getParamFilter(), $v)) {
                $arParam[$k] = '-1';
            }
        }

        return $arParam;
    }


    private function setDefaultRoutes ($arDefaultRoutes) {
        foreach ($arDefaultRoutes as $k => $v) {
            $arDefaultRoutes[$k] = strtolower($v);
        }
        $this->_arDefaultRoutes = $arDefaultRoutes;
    }


    public function getDefaultRoute ($strType) {
        return $this->_arDefaultRoutes[$strType];
    }


    private function setRequestDelimiter ($strRequestDelimiter) {
        $this->_strRequestDelimiter = $strRequestDelimiter;
    }


    public function getRequestDelimiter () {
        return $this->_strRequestDelimiter;
    }


    private function setRulesForCorrectionRequest ($arRules) {
        $this->_arRulesForCorrectionRequest = $arRules;
    }


    public function getRulesForCorrectionRequest () {
        return $this->_arRulesForCorrectionRequest;
    }


    private function setParamFilter ($arParamFilter) {
        $this->_arParamFilter = $arParamFilter;
    }


    public function getParamFilter () {
        return $this->_arParamFilter;
    }
}